package com.hnit.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hnit.exception.StatusNoPassException;
import com.hnit.mapper.OrdersMapper;
import com.hnit.mapper.ProductMapper;
import com.hnit.mapper.UserMapper;
import com.hnit.service.JwtTokenUtil;
import com.hnit.service.UserService;
import com.hnit.utils.AuthRequest;
import com.hnit.utils.AuthResponse;
import com.hnit.web.Clients.IdServiceClient;
import com.hnit.web.Clients.UploadServiceClient;
import com.hnit.web.DTO.UserDTO;
import com.hnit.web.Utils.ResponseResult;
import com.hnit.web.Utils.SHAUtils;
import com.hnit.web.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    //注入UserMapper
    @Autowired
    private UserMapper userMapper;

    //注入id生成Feign
    @Autowired
    private IdServiceClient idServiceClient;

    //注入upload服务
    @Autowired
    private UploadServiceClient uploadServiceClient;

    //注入JWT工具类
    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    //注入订单Mapper
    @Autowired
    private OrdersMapper orderMapper;

    //注入商品Mapper
    @Autowired
    private ProductMapper productMapper;

    //token生成值
    @Value("${token.secret}")
    private String secret; // 确保字段声明正确

    /**
     * 插入用户，使用 Feign 调用生成分布式 ID，并处理头像文件
     */
    @Transactional  //事务
    public ResponseResult insertUser(UserDTO userDTO) {
        //检查用户名是否合法
        if (cheakUserName(userDTO.getUserName()).getCode() != 1) {
            throw new IllegalArgumentException("用户名已存在: " + userDTO.getUserName());
        }
        ;

        try {
            // 1. 调用 Feign 客户端生成 ID
            ResponseResult idResult = idServiceClient.getNextId();

            // 2. 检查 ID 生成是否成功
            if (idResult.getCode() != 1) {
                log.error("生成用户 ID 失败: {}", idResult.getMsg());
                return ResponseResult.error("生成用户 ID 失败");
            }

            // 3. 从响应中提取 ID（假设返回的 data 是 Long 类型的 ID）
            Long userId = (Long) idResult.getData();
            if (userId == null) {
                log.error("生成的用户 ID 为空");
                return ResponseResult.error("生成的用户 ID 为空");
            }
            // 头像上传处理
            ResponseResult avatarFileRR = this.uploadServiceClient.uploadFile(new MultipartFile[]{userDTO.getAvatarFile()});
            if (avatarFileRR.getCode() != 1) {
                throw new RuntimeException("头像上传失败!");
            }
            List<String> avatarFile = (List<String>) avatarFileRR.getData();

            // 创建用户对象
            User user = new User();
            // 设置ID
            user.setUserId(userId);
            // 设置用户名
            user.setUserName(userDTO.getUserName());
            // 设置加密密码
            user.setUserPassword(SHAUtils.sha256(userDTO.getUserPassword())); //sha256 加密密码
            user.setMobile(userDTO.getMobile());  //设置手机号
            user.setEmail(userDTO.getEmail());  //设置邮箱
            user.setGender(userDTO.getGender());  //设置性别
            user.setUserStatus(1); // 默认设置用户状态为正常
            user.setRoles("CUST"); // 默认角色
            user.setAvatar(avatarFile.get(0)); // 设置头像

            // 插入用户到数据库
            int result = userMapper.insert(user);

            if (result > 0) {
                log.info("用户插入成功，ID: {}", userId);
                return ResponseResult.ok("用户创建成功").setData(user);
            } else {
                log.error("用户插入失败");
                return ResponseResult.error("用户创建失败");
            }

        } catch (Exception e) {
            log.error("插入用户时发生异常", e);
            return ResponseResult.error("系统异常，请稍后重试");
        }
    }

    /**
     * 用户登录，验证用户名和密码，成功后生成 JWT token
     */
    public AuthResponse login(AuthRequest authRequest) throws NoSuchAlgorithmException {
        String userName = authRequest.getUserName();
        String userPassword = authRequest.getUserPassword();
        // 1. 根据用户名查询用户
        User user = userMapper.findByUsername(userName);
        if (user == null) {
            log.error("用户 {} 不存在", userName);
            throw new IllegalArgumentException("Invalid username or password.");
        }else if(user.getUserStatus() == 0){
            throw new StatusNoPassException("用户已被禁用,请联系管理员");
        }

        // 2. 验证密码（假设数据库中存储的是 SHA256 加密后的密码）
        String encryptedPassword = SHAUtils.sha256(userPassword);
        if (!user.getUserPassword().equals(encryptedPassword)) {
            log.error("用户 {} 密码错误", userName);
            throw new IllegalArgumentException("Invalid username or password.");
        }

        // 3. 生成 JWT token
        // 登录成功，生成 JWT Token
        // 将逗号分隔的角色字符串转换为 Set<String> 传递给 JWT 工具  读取角色
        Set<String> rolesSet = Arrays.stream(user.getRoles().split(","))
                .map(String::trim)
                .collect(Collectors.toSet());

        // 生成 JWT Token
        String token = jwtTokenUtil.generateToken(user.getUserId(), user.getUserName(), rolesSet);
        return new AuthResponse(token, convertToDto(user));
    }

    /**
     * 用户注销（通常是客户端删除 Token，服务端无状态）。
     * 如果需要黑名单机制，可以在此实现。
     * @param token 待注销的 token
     */
    public void logout(String token) {
        // 对于无状态 JWT，注销通常意味着客户端删除其本地存储的 Token。
        // 如果需要服务器端强制注销（例如，将 Token 加入黑名单），可以在这里实现。
        // 例如：jwtTokenUtil.addToBlacklist(token);
        System.out.println("User logout (client-side token deletion assumed). Token: " + token);
    }

    /**
     * 获取所有用户信息 (仅限管理员)。
     *
     * @return 用户DTO列表
     */
    @Override
    public IPage<UserDTO> getAllUsers(int pageNum, int pageSize, String userName, String email, Integer userStatus) {
        // 1. 创建分页对象
        Page<User> page = new Page<>(pageNum, pageSize);

        // 2. 构建动态查询条件
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();

        // 如果 userName 不为空，则添加模糊查询条件
        if (userName != null && !userName.isEmpty()) {
            queryWrapper.like(User::getUserName, userName);
        }

        // 如果 email 不为空，则添加模糊查询条件
        if (email != null && !email.isEmpty()) {
            queryWrapper.like(User::getEmail, email);
        }

        // 如果 userStatus 不为空，则添加精确查询条件
        if (userStatus != null) {
            queryWrapper.eq(User::getUserStatus, userStatus);
        }

        // 3. 执行分页查询
        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        // 4. 转换为 DTO 列表
        List<UserDTO> userDTOList = userPage.getRecords().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());

        // 5. 构建分页结果
        IPage<UserDTO> userDTOIPage = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        userDTOIPage.setRecords(userDTOList);

        return userDTOIPage;
    }



    @Override
    @Transactional
    public UserDTO updatePassword(Long userId, String oldPassword, String newPassword) throws IllegalArgumentException, NoSuchAlgorithmException {
        // 1. 根据用户ID查询现有用户信息
        User existingUser = userMapper.selectById(userId);
        if (existingUser == null) {
            log.warn("尝试更新不存在的用户，ID: {}", userId);
            throw new IllegalArgumentException("用户不存在");
        }

        // 2. 验证旧密码
        String encryptedOldPassword = SHAUtils.sha256(oldPassword);
        if (!existingUser.getUserPassword().equals(encryptedOldPassword)) {
            log.warn("用户 {} 尝试使用错误的旧密码更新密码", existingUser.getUserName());
            throw new IllegalArgumentException("旧密码不正确");
        }

        // 3. 加密新密码并更新
        String hashedPassword = SHAUtils.sha256(newPassword);
        existingUser.setUserPassword(hashedPassword);

        // 4. 更新数据库
        userMapper.updateById(existingUser);

        log.info("用户 {} 密码更新成功", existingUser.getUserName());
        return convertToDto(existingUser);
    }

    @Override
    public ResponseResult updateUserStatus(Long userId, String status) throws IllegalArgumentException {
        // 1. 根据用户ID查询现有用户信息
        User existingUser = userMapper.selectById(userId);
        if (existingUser == null) {
            log.warn("尝试更新不存在的用户，ID: {}", userId);
            throw new IllegalArgumentException("用户不存在");
        }

        // 2. 更新用户状态
        existingUser.setUserStatus(Integer.valueOf(status));

        // 3. 更新数据库
        userMapper.updateById(existingUser);

        log.info("用户 {} 状态更新成功", existingUser.getUserName());
        return ResponseResult.ok("状态更新成功").setData(existingUser);
    }

    /**
     * "totalUsers": 123,       // 总用户数
     *     "totalProducts": 456,    // 总商品数
     *     "totalOrders": 789,      // 总订单数
     *     "totalRevenue": 12345.67 // 总营业额
     * @return
     */
    @Override
    public Map<String, Object> getAdminStatistics() {
        // 1. 统计总用户数
        long totalUsers = userMapper.selectCount(null);

        // 2. 统计总商品数
        long totalProducts = productMapper.selectCount(null);

        // 3. 统计总订单数
        long totalOrders = orderMapper.selectCount(null);

        // 4. 统计总营业额
        BigDecimal totalRevenue = orderMapper.getTotalRevenue();

        // 5. 构建结果 Map
        Map<String, Object> statistics = new HashMap<>();
        statistics.put("totalUsers", totalUsers);
        statistics.put("totalProducts", totalProducts);
        statistics.put("totalOrders", totalOrders);
        statistics.put("totalRevenue", totalRevenue);

        return statistics;
    }

    @Override
    /**
     * 根据用户ID查询用户信息。
     * @param id 用户ID
     * @return 用户DTO
     */
    //Optional 允许为空，会包装一下
    public Optional<UserDTO> getUserById(Long id) {
        User user = userMapper.selectById(id); // 使用 MyBatis Plus 的 selectById
        return Optional.ofNullable(user).map(this::convertToDto);
    }

    @Override
    public ResponseResult cheakUserName(String username) {
        try {
            // 1. 根据用户名查询用户
            User user = userMapper.findByUsername(username);
            if (user == null) {
                log.info("检查用户名不存在,可用", username);
                return ResponseResult.ok("用户名可用");
            } else {
                log.error("检查用户名已存在", username);
                return ResponseResult.error("用户名已存在");
            }
        } catch (Exception ex) {
            log.error("检查用户名时发生异常", ex);
            return ResponseResult.error("系统异常，请稍后重试");
        }

    }

    @Override
    @Transactional // 确保更新操作在事务中进行
    public UserDTO updateUser(Long userId, UserDTO userDTO) {
        // 1. 根据用户ID查询现有用户信息
        User existingUser = userMapper.selectById(userId);
        if (existingUser == null) {
            log.warn("尝试更新不存在的用户，ID: {}", userId);
            throw new IllegalArgumentException("用户不存在");
        }

        // 2. 检查并更新用户名
        // 如果DTO中的用户名不为空且与现有用户名不同
        if (userDTO.getUserName() != null && !userDTO.getUserName().isEmpty() && !userDTO.getUserName().equals(existingUser.getUserName())) {
            // 检查新用户名是否已存在
            if (checkUsernameExists(userDTO.getUserName())) {
                throw new IllegalArgumentException("新用户名已存在：" + userDTO.getUserName());
            }
            existingUser.setUserName(userDTO.getUserName());
        }

        // 1. 检查新手机号是否已存在于其他用户
        User existingUserWithMobile = userMapper.selectByMobile(userDTO.getMobile());

        // 2. 如果找到了一个用户使用了这个手机号，并且这个用户不是当前要更新的用户，则抛出异常
        if (existingUserWithMobile != null && !existingUserWithMobile.getUserId().equals(userId)) {
            throw new DuplicateKeyException("手机号码已被使用。");
        }

        // 3. 检查并更新密码
        // 如果DTO中的密码不为空，则对新密码进行加密
        if (userDTO.getUserPassword() != null && !userDTO.getUserPassword().isEmpty()) {
            try {
                // 使用 SHA-256 对密码进行加密
                String hashedPassword = SHAUtils.sha256(userDTO.getUserPassword());
                existingUser.setUserPassword(hashedPassword);
            } catch (NoSuchAlgorithmException e) {
                log.error("密码加密失败", e);
                throw new RuntimeException("密码更新失败");
            }
        }

        // 4. 检查并更新头像文件
        MultipartFile avatarFile = userDTO.getAvatarFile();
        if (avatarFile != null && !avatarFile.isEmpty()) {
            // 模拟调用上传服务，获取头像URL
            // TODO: 这里需要根据你的UploadServiceClient实际接口进行修改
            ResponseResult newAvatarUrl = uploadServiceClient.uploadFile(new MultipartFile[]{userDTO.getAvatarFile()});
            if (newAvatarUrl.getCode() != 1) {
                throw new RuntimeException("头像上传失败!");
            }

            existingUser.setAvatar(newAvatarUrl.getData().toString().replaceAll("^\\[|\\]$", "")
                    .replace("\\", "/"));
        }
        // 如果DTO中的头像URL不为空，且没有上传文件，则直接使用URL
        else if (userDTO.getAvatar() != null && !userDTO.getAvatar().isEmpty()) {

            String sanitizedAvatarUrl = userDTO.getAvatar();

            existingUser.setAvatar(sanitizedAvatarUrl);
        }

        // 5. 检查并更新其他字段
        Optional.ofNullable(userDTO.getMobile()).ifPresent(existingUser::setMobile);
        Optional.ofNullable(userDTO.getEmail()).ifPresent(existingUser::setEmail);
        Optional.ofNullable(userDTO.getGender()).ifPresent(existingUser::setGender);
        Optional.ofNullable(userDTO.getUserStatus()).ifPresent(existingUser::setUserStatus);

        // 6. 角色更新（通常只有管理员能修改角色）
        if (userDTO.getRoles() != null && !userDTO.getRoles().isEmpty()) {
            // 将 Set<String> 转换为逗号分隔的字符串
            existingUser.setRoles(String.join(",", userDTO.getRoles()));
        }

        // 7. 使用 MyBatis Plus 的 updateById 更新数据库
        userMapper.updateById(existingUser);

        // 8. 返回转换后的DTO
        return convertToDto(existingUser);
    }



    // 辅助方法：将 User 实体转换为 UserDTO
    private UserDTO convertToUserDTO(User user) {
        // 这里实现转换逻辑
        // 例如：BeanUtils.copyProperties(user, new UserDTO());
        return new UserDTO();
    }

    /**
     * 辅助方法：检查用户名是否已存在
     * @param username 要检查的用户名
     * @return 如果存在返回true，否则返回false
     */
    private boolean checkUsernameExists(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", username);
        // 如果查到记录，则用户名已存在
        return userMapper.exists(queryWrapper);
    }

    /**
     * 辅助方法：将 User 实体转换为 UserDTO。
     * @param user 待转换的 User 实体
     * @return 转换后的 UserDTO
     */
    private UserDTO convertToDto(User user) {
        UserDTO dto = new UserDTO();
        dto.setUserId(user.getUserId());
        dto.setUserName(user.getUserName());
        dto.setMobile(user.getMobile());
        dto.setEmail(user.getEmail());
        dto.setAvatar(user.getAvatar());
        dto.setGender(user.getGender());
        dto.setUserStatus(user.getUserStatus());

        // 将逗号分隔的角色字符串转换为 Set<String>
        if (user.getRoles() != null && !user.getRoles().isEmpty()) {
            dto.setRoles(Arrays.stream(user.getRoles().split(","))
                    .map(String::trim)
                    .collect(Collectors.toSet()));
        } else {
            dto.setRoles(Collections.emptySet());
        }
        return dto;
    }


}